package algostruct

import (
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"fmt"
)

// INullable 是一个泛型接口，表示可以表示任何类型的 NULL 值
type INullable[T any] interface {
	// 实现了数据库驱动的 Value 扫描功能，允许将数据库中的值转换为Nullable类型
	sql.Scanner

	// 实现了数据库驱动的 Value 接口，用于将Nullable类型转换为数据库驱动期望的值
	driver.Valuer

	// 实现了json.Marshaler接口，用于将Nullable类型值转换为JSON格式
	json.Marshaler

	// 实现了json.Unmarshaler接口，用于将JSON格式的数据转换为Nullable类型值
	json.Unmarshaler

	fmt.Stringer

	//
	// 返回值:
	//   bool: 如果当前对象为零值，则返回true；否则返回false。
	IsZero() bool

	// 用于获取Nullable类型内部存储的值
	Get() (T, bool)

	// 用于获取Nullable类型内部存储的值，如果未设置，则返回默认值
	GetOrElse(defaultVal T) T

	// 用于判断 Nullable 类型内部的值是否未设置
	IsNull() bool
	// 用于判断 Nullable 类型内部的值是否已设置
	IsNotNull() bool

	// 用于设置某个类型的值
	Set(val T)

	// 用于将值设置为NULL
	SetNull()
}

type Nullable[T any] struct {
	INullable[T]
	value   T
	valid   bool
	present bool
}

func NewNullable[T any](value T) Nullable[T] {
	return Nullable[T]{
		value:   value,
		valid:   true,
		present: true,
	}
}

// Scan 实现 sql.Scanner 接口
func (n *Nullable[T]) Scan(src any) error {
	n.present = true
	if src == nil {
		var zero T
		n.value, n.valid = zero, false
		return nil
	}

	if scanner, ok := any(n.Value).(sql.Scanner); ok {
		if err := scanner.Scan(src); err != nil {
			return err
		}
		n.valid = true
		return nil
	}

	n.valid = true
	switch v := src.(type) {
	case T:
		n.value = v
	default:
		return fmt.Errorf("unsupported type: %T", src)
	}
	return nil
}

// Value 实现 driver.Valuer 接口
func (n *Nullable[T]) Value() (driver.Value, error) {
	if !n.valid {
		return nil, nil
	}
	if valuer, ok := any(n.value).(driver.Valuer); ok {
		return valuer.Value()
	}
	return n.value, nil
}

// MarshalJSON 实现 json.Marshaler 接口
func (n *Nullable[T]) MarshalJSON() ([]byte, error) {
	if !n.valid {
		return []byte("null"), nil
	}
	return json.Marshal(n.value)
}

// UnmarshalJSON 实现 json.Unmarshaler 接口
func (n *Nullable[T]) UnmarshalJSON(data []byte) error {
	n.present = true
	if string(data) == "null" {
		n.valid = false
		return nil
	}
	n.valid = true
	return json.Unmarshal(data, &n.value)
}

// String 实现 fmt.Stringer 接口
func (n *Nullable[T]) String() string {
	if !n.valid {
		return "NULL"
	}
	return fmt.Sprintf("%v", n.value)
}

// IsZero 判断 nullable 类型的值是否为零值。
// 此方法主要用于检查类型 T 的值是否被设置（即是否存在）。
// 返回值为布尔类型，如果值未被设置，则返回 true，否则返回 false。
func (n *Nullable[T]) IsZero() bool {
	return !n.present
}

// Get 获取值及其有效性状态
func (n *Nullable[T]) Get() (T, bool) {
	return n.value, n.valid
}

// GetOrElse 获取值，如果无效则返回默认值
func (n *Nullable[T]) GetOrElse(defaultVal T) T {
	if n.valid {
		return n.value
	}
	return defaultVal
}

// IsNull 检查值是否为 NULL
func (n *Nullable[T]) IsNull() bool {
	return !n.valid
}

// IsNotNull 检查值是否不为 NULL
func (n *Nullable[T]) IsNotNull() bool {
	return n.valid
}

// Set 设置值
func (n *Nullable[T]) Set(val T) {
	n.value, n.valid, n.present = val, true, true
}

// SetNull 将值设置为 NULL
func (n *Nullable[T]) SetNull() {
	var zero T
	n.value, n.valid = zero, false
}
